#include <cstring>
#include <fstream>
#include <iostream>
#include <algorithm>
#include "ti.h"
#include "tplate.h"
#include "taxonomy_tree.h"

using namespace std;

void init_sim_grid(target_grid * grid, int length, int width,
                   int max_scale, int NR_cate, char *sfile)
{
    grid->max_scale = max_scale;
    grid->length = new int[max_scale];
    grid->width = new int[max_scale];
    grid->length[0] = length;
    grid->width[0] = width;
    grid->NR_cate = NR_cate;
    grid->hard_data = new int[length * width];
    ifstream ifs;
    ifs.open(sfile);
    int NR_sample;
    ifs >> NR_sample;
    memset(grid->hard_data, -1, sizeof(int) * length * width);
    for (int i = 0; i < NR_sample; i++)
    {
        int x, y;
        ifs >> x;
        ifs >> y;
        ifs >> grid->hard_data[x * width + y];
    }
    ifs.close();
    grid->sample = new target_grid_DATA[max_scale];
    for (int g = 0; g < max_scale; g++)
    {
        int cur_length = grid->length[g] = (length >> g);
        int cur_width = grid->width[g] = (width >> g);
        int unit_size = (1 << g);
        target_grid_DATA *cur_sample = grid->sample + g;
        cur_sample->category = new int[cur_length * cur_width * NR_cate];
        cur_sample->prob = new float[cur_length * cur_width * NR_cate];
        memset(cur_sample->category, 0,
               sizeof(int) * cur_length * cur_width * NR_cate);
        memset(cur_sample->prob, 0,
               sizeof(int) * cur_length * cur_width * NR_cate);
        // ensample to higher scale grid
        for (int x = 0; x < length; x++)
        {
            for (int y = 0; y < width; y++)
            {
                int cur_cate = grid->hard_data[x * width + y];
                if (-1 == cur_cate)
                    continue;
                if ((y / unit_size) >= cur_width)
                    continue;
                if ((x / unit_size) >= cur_length)
                    continue;
                cur_sample->category[(x / unit_size) *
                                     cur_width * NR_cate +
                                     (y / unit_size) * NR_cate +
                                     cur_cate] += 1;
            }
        }
    }
    return;
}

void init_sim_grid(target_grid * grid, int length, int width,
                   int max_scale, int NR_cate, int NR_sample, int *sample)
{
    grid->max_scale = max_scale;
    grid->length = new int[max_scale];
    grid->width = new int[max_scale];
    grid->length[0] = length;
    grid->width[0] = width;
    grid->NR_cate = NR_cate;
    grid->hard_data = new int[length * width];
    //memcpy(grid->hard_data, sample, sizeof(int) * length * width);
    for (int x = 0; x < length; ++x)
    {
        for (int y = 0; y < width; ++y)
        {
            grid->hard_data[x * width + y] = sample[y * length + x];
        }
    }
    grid->sample = new target_grid_DATA[max_scale];
    for (int g = 0; g < max_scale; g++)
    {
        int cur_length = grid->length[g] = (length >> g);
        int cur_width = grid->width[g] = (width >> g);
        int unit_size = (1 << g);
        target_grid_DATA *cur_sample = grid->sample + g;
        cur_sample->category = new int[cur_length * cur_width * NR_cate];
        cur_sample->prob = new float[cur_length * cur_width * NR_cate];
        memset(cur_sample->category, 0,
               sizeof(int) * cur_length * cur_width * NR_cate);
        memset(cur_sample->prob, 0,
               sizeof(int) * cur_length * cur_width * NR_cate);
        // ensample to higher scale grid
        for (int x = 0; x < length; x++)
        {
            for (int y = 0; y < width; y++)
            {
                int cur_cate = grid->hard_data[x * width + y];
                if (-1 == cur_cate)
                    continue;
                if ((y / unit_size) >= cur_width)
                    continue;
                if ((x / unit_size) >= cur_length)
                    continue;
                cur_sample->category[(x / unit_size) *
                                     cur_width * NR_cate +
                                     (y / unit_size) * NR_cate +
                                     cur_cate] += 1;
            }
        }
    }
    return;
}

int *zoom_in(int *orig_cimg, int orig_xsize, int orig_ysize, int scale,
             int NR_cate)
{
    int G = 1 << scale;
    int xsize = orig_xsize / G;
    int ysize = orig_ysize / G;
    //cout<<xsize<<" "<<ysize<<endl;
    int *zoomed = new int[xsize * ysize * NR_cate];
    memset(zoomed, 0, xsize * ysize * NR_cate * sizeof(int));
    for (int origi = 0; origi < orig_xsize; origi++)
    {
        int i = origi / G;
        if (i >= xsize)
            continue;            //去掉不够一个cell的大小
        for (int origj = 0; origj < orig_ysize; origj++)
        {
            int j = origj / G;
            if (j >= ysize)
                continue;        //去掉不够一个cell的大小
            zoomed[i * ysize * NR_cate + j * NR_cate +
                   orig_cimg[origi * orig_ysize + origj]]++;
        }
    }
    return zoomed;
}

void build_zoomed_images(int maxscale, train_grid * ti)
{
    ti->max_scale = maxscale;
    for (int g = 1; g < maxscale; g++)
    {
        int G = 1 << g;
        ti->map_cate[g].length = ti->length / G;
        ti->map_cate[g].width = ti->width / G;
        ti->map_cate[g].NR_cate = ti->NR_cate;
        ti->map_cate[g].data =
            zoom_in(ti->data, ti->length, ti->width, g, ti->NR_cate);
    }
}

void read_image(train_grid * ti, char *file)
{
    string type;
    int tmp, NR_cate;
    NR_cate = 0;
    fstream fs;
    fs.open(file);
    fs >> ti->width;
    fs >> ti->length;
    int height;                    // When in 2D, the height is always 1;
    fs >> height;
    fs >> tmp;
    fs >> type;
    int size = (ti->length) * (ti->width) * height;
    ti->data = new int[size];
    for (int i = 0; i < size; i++)
    {
        fs >> (ti->data)[i];
        NR_cate = max(NR_cate, ti->data[i] + 1);
    }
    fs.close();
}
